extends Node2D

var viewportSize
var viewportWidth
var viewportHeight
var ratioViewPort

var screenSize 
var screenWidth
var screenHeight
var ratioScreen
var cellSize = 16

var windowSize
var windowPosition


func _ready():
	viewportSize = get_viewport_rect().size
	viewportWidth = viewportSize.x
	viewportHeight = viewportSize.y
	ratioViewPort = viewportWidth * 1.0 / viewportHeight
	
	screenSize = DisplayServer.screen_get_size()
	screenWidth = screenSize.x
	screenHeight = screenSize.y
	ratioScreen = screenWidth * 1.0 / screenHeight	
	
	windowSize = DisplayServer.window_get_size()
	windowPosition = DisplayServer.window_get_position()
	
	pass


func changeScrennOrientation2Landscape():
	DisplayServer.screen_set_orientation(DisplayServer.SCREEN_LANDSCAPE)


func changeScrennOrientation2Portrait():
	DisplayServer.screen_set_orientation(DisplayServer.SCREEN_PORTRAIT)


func changeScene(sceneName):
	get_tree().current_scene.queue_free()
	var sceneInstance = ResourcePreload.resources[sceneName].instantiate() 
	get_tree().root.add_child(sceneInstance) 
	get_tree().current_scene = sceneInstance


func createSceneInst(sceneName):
	return ResourcePreload.resources[sceneName].instantiate() 	


func getSoundStream(soundName):
	return ResourcePreload.resources[soundName]
	
	
func isOSWindows():
	var osName = OS.get_name()
	return osName == "Windows"
	

func exitGame():
	get_tree().quit()
	
	
func angle2Vector(angDeg):
	var angRad = deg_to_rad(angDeg)
	var result = Vector2(cos(angRad), sin(angRad))
	return result.normalized()
	

func vector2Angle(vec:Vector2):
	var angRad = vec.angle()
	return rad_to_deg(angRad)
	

func angle2Positive(angle):
	var result = angle
	if result < 0:
		result += 360.0
	return result


func getMousePosition():
	var result = DisplayServer.mouse_get_position()
	
	if DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_FULLSCREEN:
		var targetScreenSize:Vector2 = screenSize
		if ratioScreen < ratioViewPort:
			targetScreenSize.y = targetScreenSize.x / ratioViewPort
			var offsetScreenY = (screenSize.y - targetScreenSize.y) / 2.0
			result.y -= offsetScreenY
		else:
			targetScreenSize.x = targetScreenSize.y * ratioViewPort
			var offsetScreenX = (screenSize.x - targetScreenSize.x) / 2.0
			result.x -= offsetScreenX
		
		result.x = (result.x * 1.0 / targetScreenSize.x) * viewportSize.x
		result.y = (result.y * 1.0 / targetScreenSize.y) * viewportSize.y
		
	elif DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_WINDOWED:
		result -= windowPosition
		
		result.x = (result.x * 1.0 / windowSize.x) * viewportSize.x
		result.y = (result.y * 1.0 / windowSize.y) * viewportSize.y
		
	return result
	

func worldPos2ViewPos(worldPos, cam):
	var camPos = getCamPosition(cam)
	return Vector2(worldPos.x - camPos.x, worldPos.y - camPos.y)
	
	
func view2WorldPos(viewPos, cam):
	var camPos = getCamPosition(cam)
	return Vector2(viewPos.x + camPos.x, viewPos.y + camPos.y)	

	
func getCamPosition(cam:Camera2D):
	var _viewportSize = get_viewport().get_visible_rect().size
	return Vector2(cam.offset.x - _viewportSize.x / 2.0, cam.offset.y - _viewportSize.y / 2.0)
	

func setCamPosition(cam:Camera2D, pos):
	var _viewportSize = get_viewport().get_visible_rect().size
	cam.offset = Vector2(pos.x + _viewportSize.x / 2.0, pos.y + _viewportSize.y / 2.0)


func debug(msg):
	var timeDict = Time.get_datetime_dict_from_system()
	var timeStr = "%d-%02d-%02d %02d:%02d:%02d" % [timeDict["year"], timeDict["month"], timeDict["day"], timeDict["hour"], timeDict["minute"], timeDict["second"]]
	print(timeStr, " ", msg)
	
	
func parseSequenceCommand(inputStr: String) -> Dictionary:
	var pattern = r'(\w+)\((.*)\)'
	var regex = RegEx.new()
	regex.compile(pattern)
	
	var match = regex.search(inputStr)
	if match:
		var methodName = match.get_string(1)
		var paramsStr = match.get_string(2)
		
		var params = []
		var paramPattern = r'"([^"]*)"'
		var paramRegex = RegEx.new()
		paramRegex.compile(paramPattern)
		
		var paramMatches = paramRegex.search_all(paramsStr)
		for paramMatch in paramMatches:
			params.append(paramMatch.get_string(1))
		
		return {
			"methodName": methodName,
			"params": params
		}
	else:
		push_error("输入字符串格式不正确")
		return {}
		
		
func loadCSV(filePath):
	var file = FileAccess.open(filePath, FileAccess.READ)
	var data = []
	
	if not file:
		print("文件不存在：" + filePath)
		return null
		
	while not file.eof_reached():
		var line = file.get_csv_line()
		if line.size() > 0 and not (line.size() == 1 and line[0] == ""):
			data.append(line)
			
	file.close()
	
	return data
	

func pathJoin(path1:String, path2:String):
	if path1.ends_with("/"):
		return path1 + path2
	else:
		return path1 + "/" + path2
		

func parseCSV(data:Array, clz):
	var result = []
	var configs = []
	var configsDict = {}
	
	if data.size() < 2:
		print("CSV文件内容不正确", data)
		return null
		
	var headers = data[0]
	for i in range(1, data.size()):
		var line = data[i]
		if line.size() == 0:
			continue
			
		var inst = clz.new()
		for j in range(line.size()):
			var field = headers[j]
			inst.set(field, str(line[j]))
		
		configs.append(inst)
		configsDict[line[0]] = inst
	
	result.append(configs)
	result.append(configsDict)
		
	return result


enum ITEM_TYPE{
	HEAL_ITEM,
	SKILL,
	MAGIC,
	WEAPON,
	EQUIPMENT
}

var str2ItemTypeEnumDict = {
	"HEAL_ITEM": ITEM_TYPE.HEAL_ITEM,
	"SKILL": ITEM_TYPE.SKILL,
	"MAGIC": ITEM_TYPE.MAGIC,
	"WEAPON": ITEM_TYPE.WEAPON,
	"EQUIPMENT": ITEM_TYPE.EQUIPMENT
}


func str2Vec(_str:String):
	var x = float(_str.split(',')[0]) 
	var y = float(_str.split(',')[1])
	return Vector2(x, y)


func transiteScene(configId):
	var sceneTransitionConfig = ConfigClasses.SceneTransitionConfig.configsDict[configId]
	var sceneResource = sceneTransitionConfig.sceneResource
	var npcGroupId = sceneTransitionConfig.npcGroup
	var sceneNPCConfigGroup = ConfigClasses.SceneNPCConfig.groupConfigArrDict[npcGroupId]
	
	var playerPos = str2Vec(sceneTransitionConfig.playerPos) 
	var playerFace = sceneTransitionConfig.playerFace
	
	Global.changeScene(sceneResource)
	
	for sceneNPCConfig in sceneNPCConfigGroup:
		var npcId = sceneNPCConfig.npcId
		var npcConfig = ConfigClasses.NPCConfig.configsDict[npcId]
		var npcPos = Vector2(float(sceneNPCConfig.locationX), float(sceneNPCConfig.locationY))
		var npcFace = sceneNPCConfig.face
		var npcResource = "NPC"
		
		var npcInst = Global.createSceneInst(npcResource)
		get_tree().current_scene.add_child(npcInst)
		npcInst.init(npcPos, npcFace, npcConfig.spriteFrames, npcConfig)
		
	var playerInst = Global.createSceneInst(Consts.RESOURCE_PLAYER)
	get_tree().current_scene.add_child(playerInst)
	playerInst.setSpriteFrames(GlobalData.playerData.spriteFrames)
	playerInst.setPosAndFace(playerPos, playerFace)
	
	var camera = tryGetCurrentSceneCamera()
	if camera: camera.tryGetCamFollowTarget()
	
	initPartnerView(playerInst)
	
	
func initPartnerView(followTarget):
	if GlobalData.partnersData.size() <= 0:
		return
		
	var nextFollowTarget = followTarget

	for partnerData in GlobalData.partnersData:
		var inst = Global.createSceneInst(Consts.RESOURCE_PARTNER)
		get_tree().current_scene.add_child(inst)
		inst.setSpriteFrames(partnerData.spriteFrames)
		inst.setData(partnerData)
		
		#for test
		inst.setFollowTarget(nextFollowTarget)
		nextFollowTarget = inst
	

func tryGetCurrentSceneCamera():
	return getChildNodeByName(get_tree().current_scene, Consts.SCENE_CAMERA_NAME)

	
func getChildNodeByName(parentNode:Node2D, childNodeName):
	for index in range(parentNode.get_child_count()):
		var childNode = parentNode.get_child(index) 
		if childNodeName in childNode.name:
			return childNode
	return null
	

func dir2Face(dir:Vector2):
	var face = "Down"
	var angle = dir.angle() / PI * 180.0
	
	if angle <= 45 and angle >= -45:
		face = "Right"
	
	if angle > 45 and angle < 135:
		face = "Down"
		
	if angle >= 135 and angle <= 180:
		face = "Left"
		
	if angle < -45 and angle > -135:
		face = "Up"
	
	if angle <= -135 and angle >= -180:
		face = "Left"
		
	return face
	
	
func createIconAtlasTexture(resourceName):
	var iconConfig = ConfigClasses.IconsConfig.configsDict[resourceName]
	var iconPos = Vector2(float(iconConfig.x), float(iconConfig.y))
	
	var atlasTexture = AtlasTexture.new()
	atlasTexture.atlas = ResourcePreload.resources["Icons"]
	atlasTexture.region = Rect2(iconPos, Vector2(16, 16))
	
	return atlasTexture
	

func clearChildNode(parentNode:Node):
	for index in range(parentNode.get_child_count()):
		parentNode.get_child(index).queue_free()
	

func replacePlaceholders(text:String, values:Dictionary):
	for key in values.keys():
		text = text.replace("{" + key + "}", str(values[key]))
	return text
		

func parseMenuConfigText2Dict(config: String) -> Dictionary:
	var lines = config.split("\n", false)
	var root = {}
	var stack = []
	
	for line in lines:
		var trimmed_line = line.strip_edges()
		if trimmed_line == "":
			continue
		
		var indent_level = line.length() - trimmed_line.length()
		var menu_item = {"name": trimmed_line, "children": {}}
		
		if indent_level == 0:
			# Top level item
			root[trimmed_line] = menu_item
			stack = [menu_item]
		else:
			while indent_level < stack.size() - 1:
				stack.pop_back()
			# Add the item to the current parent's children
			stack[-1]["children"][trimmed_line] = menu_item
			stack.append(menu_item)
	
	return root
	

func parseMenuDict2MenuStructureLoop(menuDict:Dictionary, parentMenu:Array):
	for key in menuDict.keys():
		var menuItem = CustomClasses.BattleEntityCommandBoxMenuItemData.new(key)
		parentMenu.append(menuItem)
		
		var value = menuDict[key]
		if value.children.keys().size() > 0:
			parseMenuDict2MenuStructureLoop(value.children, menuItem.subMenuItemsData)
		

func parseMenuDict2MenuStructure(menuDict):
	var result = []
	
	parseMenuDict2MenuStructureLoop(menuDict, result)
	
	return result
	

func parseMenuConfigText2Structure(configText):
	var dict = parseMenuConfigText2Dict(configText)
	var result = parseMenuDict2MenuStructure(dict)
	return result
	

func captureCurrentViewTexture():
	var imageData = get_viewport().get_texture().get_image()
	return imageData
	
	
func createTextureFromImage(imageData):
	return ImageTexture.create_from_image(imageData)
	
